package com.salelogistics.sale.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.salelogistics.common.core.utils.DateUtils;
import com.salelogistics.common.core.web.domain.AjaxResult;
import com.salelogistics.common.security.utils.SecurityUtils;
import com.salelogistics.sale.domain.SmsBatchPlan;
import com.salelogistics.sale.domain.SmsBatchPlanDetails;
import com.salelogistics.sale.domain.SmsDeliveryPlan;
import com.salelogistics.sale.domain.SmsDeliveryPlanDetails;
import com.salelogistics.sale.domain.dto.DeliveryPlanDetailsDto;
import com.salelogistics.sale.domain.dto.DeliveryPlanDto;
import com.salelogistics.sale.domain.vo.DeliveryPlanVo;
import com.salelogistics.sale.mapper.SmsBatchPlanDetailsMapper;
import com.salelogistics.sale.mapper.SmsBatchPlanMapper;
import com.salelogistics.sale.mapper.SmsDeliveryPlanDetailsMapper;
import com.salelogistics.sale.mapper.SmsDeliveryPlanMapper;
import com.salelogistics.sale.service.ISmsDeliveryPlanService;
import com.salelogistics.sale.utils.RedisIdWorker;
import com.salelogistics.system.api.RemoteBasBuildUnitService;
import com.salelogistics.system.api.RemoteBasContractService;
import com.salelogistics.system.api.RemoteBasLotService;
import com.salelogistics.system.api.RemoteBasMaterialService;
import com.salelogistics.system.api.domain.BasBuildUnit;
import com.salelogistics.system.api.domain.BasContract;
import com.salelogistics.system.api.domain.BasLot;
import com.salelogistics.system.api.domain.BasMaterial;
import com.salelogistics.system.api.model.LoginUser;
import lombok.extern.flogger.Flogger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 月配送计划Service业务层处理
 *
 * @author Hu Kangying
 * @date 2023-07-13
 */
@Service
public class SmsDeliveryPlanServiceImpl extends ServiceImpl<SmsDeliveryPlanMapper, SmsDeliveryPlan> implements ISmsDeliveryPlanService {
    @Resource
    private SmsDeliveryPlanMapper smsDeliveryPlanMapper;
    @Autowired
    private SmsDeliveryPlanDetailsMapper deliveryPlanDetailsMapper;
    @Autowired
    private SmsDeliveryPlanDetailsMapper planDetailsMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RemoteBasContractService remoteBasContractService;
    @Resource
    private RemoteBasBuildUnitService remoteBasBuildUnitService;
    @Resource
    private RemoteBasMaterialService remoteBasMaterialService;
    @Resource
    private RemoteBasLotService remoteBasLotService;

    public static final int APPROVED = 1;
    public static final int DE_APPROVAL = 0;

    /**
     * 查询月配送计划
     *
     * @param planId 月配送计划主键
     * @return 月配送计划
     */
    @Override
    public SmsDeliveryPlan selectSmsDeliveryPlanByPlanId(Long planId) {
        return smsDeliveryPlanMapper.selectSmsDeliveryPlanByPlanId(planId);
    }

    /**
     * 查询月配送计划列表
     *
     * @param smsDeliveryPlan 月配送计划
     * @return 月配送计划
     */
    @Override
    public List<SmsDeliveryPlan> selectSmsDeliveryPlanList(SmsDeliveryPlan smsDeliveryPlan) {
        return smsDeliveryPlanMapper.selectSmsDeliveryPlanList(smsDeliveryPlan);
    }

    @Override
    public List<DeliveryPlanVo> selectDeliveryPlanList(SmsDeliveryPlan smsDeliveryPlan) {
        //查询月配送计划，设计Vo对象
        List<DeliveryPlanVo> deliveryPlanVos = smsDeliveryPlanMapper.queryDeliveryPlanList(smsDeliveryPlan);
        for (DeliveryPlanVo deliveryPlanVo : deliveryPlanVos) {
            Object contractData = remoteBasContractService.selectBasContractByContractId(
                    deliveryPlanVo.getContractId()).get("data");
            BasContract contract = convertJsonToBean(contractData, BasContract.class);
            deliveryPlanVo.setContractName(contract.getContractName());
            Object lotData = remoteBasLotService.selectBasLotById
                    (deliveryPlanVo.getLotSection()).get("data");
            BasLot lot = convertJsonToBean(lotData, BasLot.class);
            deliveryPlanVo.setLotSectionCode(lot.getCode());
            Object buildUnitData = remoteBasBuildUnitService.selectBasBuildUnitByBuildId
                    (deliveryPlanVo.getBuildUnitId()).get("data");
            BasBuildUnit buildUnit = convertJsonToBean(buildUnitData, BasBuildUnit.class);
            deliveryPlanVo.setBuildUnitName(buildUnit.getBuildName());
        }
        return deliveryPlanVos;
    }

    /**
     * 将json格式的对象转化为java bean对象
     *
     * @param obj       待转换为json对象
     * @param classType 要转换的javaBean对象
     * @param <T>       转换的类型
     * @return 转换成功的对象
     */
    private <T> T convertJsonToBean(Object obj, Class<T> classType) {
        JSONObject from = JSONObject.from(obj);
        T res = from.toJavaObject(classType);
        return res;
    }

    /**
     * 新增月配送计划
     *
     * @param smsDeliveryPlan 月配送计划
     * @return 结果
     */
    @Override
    public int insertSmsDeliveryPlan(SmsDeliveryPlan smsDeliveryPlan) {
        smsDeliveryPlan.setCreateTime(DateUtils.getNowDate());
        return smsDeliveryPlanMapper.insertSmsDeliveryPlan(smsDeliveryPlan);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertSmsDeliveryPlanWithDetails(DeliveryPlanDto deliveryPlanDto) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String userId = String.valueOf(loginUser.getUserid());
        SmsDeliveryPlan deliveryPlan = deliveryPlanDto.getDeliveryPlan();
        RedisIdWorker redisIdWorker = new RedisIdWorker(stringRedisTemplate);
        long id = redisIdWorker.nextId("delivery_plan");
        deliveryPlan.setPlanId(String.valueOf(id));
        deliveryPlan.setCreateBy(userId);
        insertSmsDeliveryPlan(deliveryPlan);
        //插入月配送计划基本信息
        List<DeliveryPlanDetailsDto> deliveryPlanDetails = deliveryPlanDto.getDeliveryPlanDetails();
        List<SmsDeliveryPlanDetails> planDetailsList = new ArrayList<>();
        for (DeliveryPlanDetailsDto deliveryPlanDetail : deliveryPlanDetails) {
            SmsDeliveryPlanDetails planDetails = BeanUtil.toBean(deliveryPlanDetail, SmsDeliveryPlanDetails.class);
            planDetails.setPlanId(id);
            planDetails.setCreateBy(userId);
            planDetails.setCreateTime(DateUtils.getNowDate());
            planDetails.setPlanQuantity(deliveryPlanDetail.getPlanQuantity());
            planDetailsMapper.insertSmsDeliveryPlanDetails(planDetails);
            planDetailsList.add(planDetails);
        }
        return 1;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateSmsDeliveryPlanWithDetails(DeliveryPlanDto deliveryPlanDto) {
        LoginUser user = SecurityUtils.getLoginUser();
        SmsDeliveryPlan deliveryPlan = deliveryPlanDto.getDeliveryPlan();
        int isUpdatePlan = updateSmsDeliveryPlan(deliveryPlan);
        List<DeliveryPlanDetailsDto> planDetails = deliveryPlanDto.getDeliveryPlanDetails();
        System.out.println("planDetials = " + planDetails);
        if (planDetails == null || planDetails.size() == 0) {
            return 1;
        }
        //修改之前先查一下db
        QueryWrapper<SmsDeliveryPlanDetails> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("plan_id", deliveryPlan.getPlanId());
        List<SmsDeliveryPlanDetails> planDetailsList = deliveryPlanDetailsMapper.
                selectSmsDeliveryPlanDetailsList(new SmsDeliveryPlanDetails(Long.valueOf(deliveryPlan.getPlanId())));
        System.out.println("count =  " + planDetailsList.size());
        //如果db目前还没有材料，则当前材料需要insert到db
        //if (planDetailsList.size() == planDetails.size()){
        //长度相同，类型相同的修改，类型不同的相加
        Set<Long> original = planDetailsList.stream().map(SmsDeliveryPlanDetails::getMaterialId).collect(Collectors.toSet());
        Set<Long> reception = planDetails.stream().map(DeliveryPlanDetailsDto::getMaterialId).collect(Collectors.toSet());
        Set<Long> commons = new HashSet<>(original);
        commons.retainAll(reception);
        Set<DeliveryPlanDetailsDto> commonList = planDetails.stream().
                filter(item -> commons.contains(item.getMaterialId())).
                collect(Collectors.toSet());
        for (DeliveryPlanDetailsDto planDetail : commonList) {
            SmsDeliveryPlanDetails details = BeanUtil.toBean(planDetail, SmsDeliveryPlanDetails.class);
            details.setPlanId(Long.valueOf(deliveryPlan.getPlanId()));
            details.setEditedTime(DateUtils.getNowDate());
            details.setEditedBy(user.getUserid());
            details.setMaterialId(planDetail.getMaterialId());
            details.setPlanQuantity(planDetail.getPlanQuantity());
            deliveryPlanDetailsMapper.updateSmsDeliveryPlanDetails(details);
        }

        Set<Long> diff = new HashSet<>(reception);
        diff.removeAll(original);
        Set<DeliveryPlanDetailsDto> diffList = planDetails.stream().
                filter(item -> diff.contains(item.getMaterialId())).
                collect(Collectors.toSet());
        for (DeliveryPlanDetailsDto planDetail : diffList) {
            SmsDeliveryPlanDetails details = BeanUtil.toBean(planDetail, SmsDeliveryPlanDetails.class);
            details.setPlanId(Long.valueOf(deliveryPlan.getPlanId()));
            details.setCreateTime(DateUtils.getNowDate());
            details.setCreateBy(user.getUsername());
            deliveryPlanDetailsMapper.insertSmsDeliveryPlanDetails(details);
        }
        System.out.println("common elements :" + commonList);
        System.out.println("different elements :" + diffList);
        return isUpdatePlan;
    }

    /**
     * 修改月配送计划
     *
     * @param smsDeliveryPlan 月配送计划
     * @return 结果
     */
    @Override
    public int updateSmsDeliveryPlan(SmsDeliveryPlan smsDeliveryPlan) {
        return smsDeliveryPlanMapper.updateSmsDeliveryPlan(smsDeliveryPlan);
    }


    /**
     * 批量删除月配送计划
     *
     * @param planIds 需要删除的月配送计划主键
     * @return 结果
     */
    @Override
    public int deleteSmsDeliveryPlanByPlanIds(Long[] planIds) {
        return smsDeliveryPlanMapper.deleteSmsDeliveryPlanByPlanIds(planIds);
    }

    /**
     * 删除月配送计划信息
     *
     * @param planId 月配送计划主键
     * @return 结果
     */
    @Override
    public int deleteSmsDeliveryPlanByPlanId(Long planId) {
        return smsDeliveryPlanMapper.deleteSmsDeliveryPlanByPlanId(planId);
    }

    @Override
    public int processDeliveryPlan(Long planId, boolean flag) {
        UpdateWrapper<SmsDeliveryPlan> updateWrapper = new UpdateWrapper<>();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userid = loginUser.getUserid();
        if (flag) {
            //审核
            updateWrapper.set("reviewed_status", APPROVED);
            //获取月计划信息
            List<DeliveryPlanVo> list = smsDeliveryPlanMapper.queryDeliveryPlanListWithPlanId(planId);
            //新增月计划到批计划
            System.out.println("sssoop = " + list);

        } else {
            //反审核
            updateWrapper.set("reviewed_status", DE_APPROVAL);
        }
        updateWrapper.set("reviewed_by", userid).
                set("reviewed_time", DateUtils.getNowDate()).eq("plan_id", planId);
        boolean update = update(updateWrapper);
        return update ? 1 : 0;
    }

    @Resource
    private SmsBatchPlanMapper batchPlanMapper;
    @Resource
    private SmsBatchPlanDetailsMapper batchDetailsMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int saveBatchPlan(DeliveryPlanDto deliveryPlanDto) {
        if (deliveryPlanDto == null || deliveryPlanDto.getDeliveryPlanDetails() == null
                || deliveryPlanDto.getDeliveryPlan() == null) {
            return 0;
        }
        LoginUser user = SecurityUtils.getLoginUser();
        SmsDeliveryPlan deliveryPlan = deliveryPlanDto.getDeliveryPlan();
        String planId = deliveryPlan.getPlanId();

        //批次计划插入
        SmsBatchPlan batchPlan = BeanUtil.toBean(deliveryPlan, SmsBatchPlan.class);
        batchPlan.setReviewedStatus(0L);//清空
        batchPlan.setReviewedBy(null);
        batchPlan.setReviewedTime(null);
        batchPlan.setCreateBy(user.getUsername());
        batchPlan.setCreateTime(DateUtils.getNowDate());
        batchPlan.setSupplied(BigDecimal.ZERO);
        batchPlan.setArrivalDate(deliveryPlan.getPlanMonth());
        RedisIdWorker redisIdWorker = new RedisIdWorker(stringRedisTemplate);
        long id = redisIdWorker.nextId("batch_plan");
        batchPlan.setSerialId(String.valueOf(id));
        int i = batchPlanMapper.insertSmsBatchPlan(batchPlan);
        List<DeliveryPlanDetailsDto> planDetails = deliveryPlanDto.getDeliveryPlanDetails();
        //详细材料添加
        List<SmsBatchPlanDetails> batchPlanDetails = new ArrayList<>();
        for (DeliveryPlanDetailsDto planDetail : planDetails) {
            SmsBatchPlanDetails details = BeanUtil.toBean(planDetail, SmsBatchPlanDetails.class);
            details.setBatchId(batchPlan.getSerialId());
            //拆分数量
            details.setSplitQuantity(planDetail.getDelivery());
            details.setBatched(BigDecimal.ZERO);
            details.setCreateBy(user.getUsername());
            details.setCreateTime(DateUtils.getNowDate());
            batchPlanDetails.add(details);
            batchDetailsMapper.insertSmsBatchPlanDetails(details);
            //修改计划表中的可分解数量
            deliveryPlanDetailsMapper.updateDecomposable(planId,
                    String.valueOf(planDetail.getMaterialId()),planDetail.getDelivery().toString());
            deliveryPlanDetailsMapper.updateCompletedCount(planId,String.valueOf(planDetail.getMaterialId()),
                    planDetail.getDelivery().toString());
        }
        return 1;
    }

    private List<DeliveryPlanVo> generateBatchPlan(List<DeliveryPlanVo> deliveryPlan) {

        return null;
    }
}
